/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package au.csiro.nt.psdp.model;

/**
 *
 * @author Jingyu ZHANG
 */
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.userdetails.UserDetails;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.appfuse.model.BaseObject;
import org.appfuse.model.LabelValue;

import javax.persistence.*;
import javax.persistence.SequenceGenerator;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 *
 */
@Entity
//@SequenceGenerator(name="mySequence_PRODUCT",    sequenceName="mySequence", initialValue=4, allocationSize=1)
@Table(name = "users")
public class User extends BaseObject implements Serializable, UserDetails
{
    private static final long serialVersionUID = 3832626162173359411L;

    protected Long id;
    protected String username;                    // required
    protected String password;                    // required
    protected String confirmPassword;
    protected String passwordHint;
    protected String email;
    protected Integer version;
    protected Set<Role> roles = new HashSet<Role>();
    protected boolean enabled;
    protected boolean accountExpired;
    protected boolean accountLocked;
    protected boolean credentialsExpired;

    public User()
    {
    }


    public User(String username, String password, Set<Role> roles, boolean enabled)
    {
        this.username = username;
        this.password = password;
        this.confirmPassword = password;
        this.roles = roles;
        this.enabled = enabled;

    }

    public User(String username)
    {
        this.username = username;
    }

    @Id
    @Column(name = "user_id")
    //@GeneratedValue(strategy=GenerationType.SEQUENCE,  generator="mySequence_PRODUCT")
    @GeneratedValue(strategy = GenerationType.AUTO)

    public Long getId()
    {
        return id;
    }

    @Column(nullable = false, length = 50, unique = true)
    public String getUsername()
    {
        return username;
    }

    @Column(nullable = false)
    public String getPassword()
    {
        return password;
    }

    @Transient
    public String getConfirmPassword()
    {
        return confirmPassword;
    }

    @Column(name = "password_hint")
    public String getPasswordHint()
    {
        return passwordHint;
    }
    @Column(name = "email")
    public String getEmail()
    {
        return email;
    }
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
            name = "user_role",
            joinColumns = {@JoinColumn(name = "user_id")},
            inverseJoinColumns = @JoinColumn(name = "role_id")
    )
    public Set<Role> getRoles()
    {
        return roles;

    }
//    public Set<TraderGroup> getTraderGroups()
//    {
//        return traderGroups;
//    }

    /**
     * Convert user roles to LabelValue objects for convenience.
     *
     * @return a list of  objects with role information
     */
    @Transient
    public List<LabelValue> getRoleList()
    {
        List<LabelValue> userRoles = new ArrayList<LabelValue>();

        if (this.roles != null)
        {
            for (Role role : roles)
            {
                // convert the user's roles to LabelValue Objects
                userRoles.add(new LabelValue(role.getName(), role.getName()));
            }
        }

        return userRoles;
    }

    /**
     * Adds a role for the user
     *
     * @param role the fully instantiated role
     */
    public void addRole(Role role)
    {
        getRoles().add(role);
    }

    /**
     * @see org.acegisecurity.userdetails.UserDetails#getAuthorities()
     */
    @Transient
    public GrantedAuthority[] getAuthorities()
    {
        return roles.toArray(new GrantedAuthority[0]);
    }

    @Version
    public Integer getVersion()
    {
        return version;
    }

    @Column(name = "account_enabled")
    public boolean isEnabled()
    {
        return enabled;
    }

    @Column(name = "account_expired", nullable = false)
    public boolean isAccountExpired()
    {
        return accountExpired;
    }

    /**
     * @see org.acegisecurity.userdetails.UserDetails#isAccountNonExpired()
     */
    @Transient
    public boolean isAccountNonExpired()
    {
        return !isAccountExpired();
    }

    @Column(name = "account_locked", nullable = false)
    public boolean isAccountLocked()
    {
        return accountLocked;
    }

    /**
     * @see org.acegisecurity.userdetails.UserDetails#isAccountNonLocked()
     */
    @Transient
    public boolean isAccountNonLocked()
    {
        return !isAccountLocked();
    }

    @Column(name = "credentials_expired", nullable = false)
    public boolean isCredentialsExpired()
    {
        return credentialsExpired;
    }

    /**
     * @see org.acegisecurity.userdetails.UserDetails#isCredentialsNonExpired()
     */
    @Transient
    public boolean isCredentialsNonExpired()
    {
        return !credentialsExpired;
    }

    public void setId(Long id)
    {
        this.id = id;
    }

    public void setUsername(String username)
    {
        this.username = username;
    }

    public void setPassword(String password)
    {
        this.password = password;
    }

    public void setConfirmPassword(String confirmPassword)
    {
        this.confirmPassword = confirmPassword;
    }

    public void setPasswordHint(String passwordHint)
    {
        this.passwordHint = passwordHint;
    }
    public void setEmail(String email)
    {
        this.email = email;
    }

    public void setRoles(Set<Role> roles)
    {
        this.roles = roles;
    }

//    public void setTraderGroups(Set<TraderGroup> traderGroups)
//    {
//        this.traderGroups = traderGroups;
//    }

    public void setVersion(Integer version)
    {
        this.version = version;
    }

    public void setEnabled(boolean enabled)
    {
        this.enabled = enabled;
    }

    public void setAccountExpired(boolean accountExpired)
    {
        this.accountExpired = accountExpired;
    }

    public void setAccountLocked(boolean accountLocked)
    {
        this.accountLocked = accountLocked;
    }

    public void setCredentialsExpired(boolean credentialsExpired)
    {
        this.credentialsExpired = credentialsExpired;
    }

    public boolean equals(Object o)
    {
        if (this == o) return true;
        if (!(o instanceof User)) return false;

        final User user = (User) o;

        return !(username != null ? !username.equals(user.getUsername()) : user.getUsername() != null);

    }

    public int hashCode()
    {
        return (username != null ? username.hashCode() : 0);
    }

    public String toString()
    {
        ToStringBuilder sb = new ToStringBuilder(this,
                ToStringStyle.DEFAULT_STYLE).append("username", this.username)
                .append("enabled", this.enabled)
                .append("accountExpired", this.accountExpired)
                .append("credentialsExpired", this.credentialsExpired)
                .append("accountLocked", this.accountLocked);

        GrantedAuthority[] auths = this.getAuthorities();
        if (auths != null)
        {
            sb.append("Granted Authorities: ");

            for (int i = 0; i < auths.length; i++)
            {
                if (i > 0)
                {
                    sb.append(", ");
                }
                sb.append(auths[i].toString());
            }
        }
        else
        {
            sb.append("No Granted Authorities");
        }
        return sb.toString();
    }
}
